package model.info;

import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;


import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class OSMDecoder extends Thread {

	private String consult;
	private ArrayList<MapNode> nodeList;
	private ArrayList<MapWay> wayList;
	private static Integer error = 0;
	
	public OSMDecoder() {
		
		nodeList = new ArrayList<MapNode>();
		wayList = new ArrayList<MapWay>();		
	}
	
	public ArrayList<MapNode> getNodeList() {
		return nodeList;
	}

	public void setNodeList(ArrayList<MapNode> nodeList) {
		this.nodeList = nodeList;
	}

	public ArrayList<MapWay> getWayList() {
		return wayList;
	}

	public void setWayList(ArrayList<MapWay> wayList) {
		this.wayList = wayList;
	}
	
	public void getOnLineInfo(Double left,Double down,Double right,Double up) {
		
		consult = "http://api.openstreetmap.org/api/0.6/map?bbox="+left+","+down+","+right+","+up;
		System.out.println("Consult: "+consult);
		Document document = getDocumentOSM();
		
		Node node = document.getDocumentElement();
		NodeList list = node.getChildNodes();
		for (int i=0;i<list.getLength();i++) {
			if (list.item(i).getNodeName().equals(Constants.NODE)) {
				MapNode newNode =  getNode(list.item(i));
				if (newNode != null)
					nodeList.add(newNode);
			}
			else if (list.item(i).getNodeName().equals(Constants.WAY)){
				MapWay newWay = getWay(list.item(i));
				wayList.add(newWay);
			}
		}
		for (int i=0;i<nodeList.size();i++)
			if (!nodeList.get(i).getUsed())
				nodeList.remove(i);	
	}
	
	public Document getDocumentOSM() {
		
		URL url = null;
		Document document = null;
		try {
			url = new URL(consult);
			URLConnection conn = url.openConnection();
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = factory.newDocumentBuilder();
			document = builder.parse(conn.getInputStream());
		} 
		catch (Exception e) {
			System.out.println("Failing...");
			document = getDocumentOSM();
		}
		return document;
	}
	
	public MapNode getNode(Node node) {
		
		String id = null;
		Double lat = 0.0;
		Double lon = 0.0;
		NamedNodeMap nodeMap = node.getAttributes();
		for (int i=0;i<nodeMap.getLength();i++) {
			if (nodeMap.item(i).getNodeName().equals(Constants.ID))
				id = new String(nodeMap.item(i).getNodeValue());
			else if (nodeMap.item(i).getNodeName().equals(Constants.LAT))
				lat = new Double(nodeMap.item(i).getNodeValue());
			else if (nodeMap.item(i).getNodeName().equals(Constants.LON))
				lon = new Double(nodeMap.item(i).getNodeValue());
		}
		Coordinate coordinate = null;
		try {
			coordinate = new Coordinate (lat,lon);
		} catch (CoordinateRangeException e) {
			e.printStackTrace();
		}
		MapNode newNode = new MapNode(id,coordinate);
		NodeList list = node.getChildNodes();
		for (int i=0;i<list.getLength();i++) {
			nodeMap = list.item(i).getAttributes();
			if (nodeMap !=null) {
				Integer j=0;
				while(j<nodeMap.getLength()) {
					if (nodeMap.item(j).getNodeName().equals(Constants.K)) {
						newNode.getInfo().put(nodeMap.item(j).getNodeValue(), nodeMap.item(j+1).getNodeValue());
						j = j+1;
					}
					j = j+1;
				}
			}
		}
		return newNode;
	}
	
	public MapWay getWay(Node node) {
		
		String id = "";
		NamedNodeMap nodeMap = node.getAttributes();
		Boolean found = false;
		for (int i=0;i<nodeMap.getLength()&&!found;i++) {
			if (nodeMap.item(i).getNodeName().equals(Constants.ID)) {
				id = new String(nodeMap.item(i).getNodeValue());
				found = true;
			}
		}
		MapWay way = new MapWay(id);
		NodeList list = node.getChildNodes();
	
		for (int i=0;i<list.getLength();i++) {
			nodeMap = list.item(i).getAttributes();
			if (nodeMap != null) {
				Integer j=0;
				while (j<nodeMap.getLength()) {
					if (nodeMap.item(j).getNodeName().equals(Constants.REF)) {
						String numNode = new String(nodeMap.item(j).getNodeValue());
						found = false;
						for (int k=0;k<nodeList.size() && !found;k++) {
							if (nodeList.get(k).getId().equals(numNode)) {
								way.getNodes().add(nodeList.get(k));
								nodeList.get(k).setUsed(true);
								found = true;
							}
						}
						if (!found) {
							System.out.println("Error "+error+" en: "+numNode);
							error++;
						}
					}
					else {
						if (nodeMap.item(j).getNodeName().equals(Constants.K)) {
							way.getData().put(nodeMap.item(j).getNodeValue(),nodeMap.item(j+1).getNodeValue());
							j = j+1;
						}
					}
					j = j+1;
				}
			}
		}
		return way;
	}
}
